'''
Created on 09/08/2009

@author: daniel
'''

import sys
import re
from paste import httpserver
from webob import Request, Response
from webob import exc

var_regex = re.compile(r'''
    \{          # The exact character "{"
    (\w+)       # The variable name (restricted to a-z, 0-9, _)
    (?::([^}]+))? # The optional :regex part
    \}          # The exact character "}"
    ''', re.VERBOSE)

def template_to_regex(template):
    regex = ''
    last_pos = 0
    for match in var_regex.finditer(template):
        regex += re.escape(template[last_pos:match.start()])
        var_name = match.group(1)
        expr = match.group(2) or '[^/]+'
        expr = '(?P<%s>%s)' % (var_name, expr)
        regex += expr
        last_pos = match.end()
        regex += re.escape(template[last_pos:])
        regex = '^%s$' % regex
        return regex

def load_controller(string):
    module_name, func_name = string.split(':', 1)
    __import__(module_name)
    module = sys.modules[module_name]
    func = getattr(module, func_name)
    return func

def controller(func):
    def replacement(environ, start_response):
        req = Request(environ)
        try:
            resp = func(req, **req.urlvars)
        except exc.HTTPException, e:
            resp = e
            if isinstance(resp, basestring):
               resp = Response(body=resp)
               return resp(environ, start_response)
        return replacement

def rest_controller(cls):
    def replacement(environ, start_response):
        req = Request(environ)
        try:
            instance = cls(req, **req.urlvars)
            action = req.urlvars.get('action')
            if action:
                action += '_' + req.method.lower()
            else:
                action = req.method.lower()
                try:
                    method = getattr(instance, action)
                except AttributeError:
                    raise exc.HTTPNotFound("No action %s" % action)
                    resp = method()
                    if isinstance(resp, basestring):
                        resp = Response(body=resp)
        except exc.HTTPException, e:
            resp = e
            return resp(environ, start_response)
    return replacement

class Router(object):
    def __init__(self):
        self.routes = []

    def add_route(self, template, controller, **vars):
        if isinstance(controller, basestring):
           controller = load_controller(controller)
           self.routes.append((re.compile(template_to_regex(template)),
                               controller,vars))

    def __call__(self, environ, start_response):
        req = Request(environ)
        for regex, controller, vars in self.routes:
            match = regex.match(req.path_info)
            if match:
                req.urlvars = match.groupdict()
                req.urlvars.update(vars)
                return controller(environ, start_response)
        return exc.HTTPNotFound()(environ, start_response)

#===============================================================================

@controller
def hello(req):
    if req.method == 'POST':
       return 'Hello %s!' % req.params['name']
    elif req.method == 'GET':
       return '''<form method="POST">
            You're name: <input type="text" name="name">
            <input type="submit">
            </form>'''

#===============================================================================

class Hello(object):

    def __init__(self, req):
        self.request = req
    
    def get(self):
        return '''<form method="POST">
            You're name: <input type="text" name="name">
            <input type="submit">
            </form>'''
    
    def post(self):
        return 'Hello %s!' % self.request.params['name']

hello = rest_controller(Hello)

#===============================================================================

hello_world = Router()
hello_world.add_route('/', controller=hello)

if __name__ == "__main__":
    httpserver.serve(hello_world, host="127.0.0.1", port=8080)
